#include "stdafx.h"
#include "Chunk.h"
#include "Skybox.h"
#include "..\Objects\ObjectManager.h"
#include "../World/Terrain.h"
#include "../Objects/Player/Player.h"
#include "..\Objects\GameObject.h"
#include "..\Objects/Buildings/Shrine.h"
#include "..\Particles\ParticleSystem.h"
#include "..\Particles\ParticleEmitter.h"
#include "..\Particles\ParticleEffector.h"
#include "..\..\EdgeContent\ContentManager.h"
#include "..\..\EdgeMath\Vectors.h"
#include "..\..\EdgeMath\Math.h"
#include "..\..\EdgeGraphics\Lighting\PointLight.h"
#include "..\..\EdgeGraphics\Lighting\LightingEngine.h"
#include "../Objects/Buildings/Temple.h"
#include "..\..\tinyxml\tinystr.h"
#include "..\..\tinyxml\tinyxml.h"
#include "../Objects/IAgent.h"
#include "Heightmap.h"
#include <string>
#include <iostream>

using namespace VectorHelper;

Chunk::Chunk(const char* filename)
{
	objectManager = new ObjectManager;

	TiXmlDocument* doc = new TiXmlDocument(filename);

	doc->LoadFile(filename);

	std::cout << "Loading level: " << filename << std::endl;

	TiXmlNode* root = doc->FirstChild();
	root = root->NextSibling();

	// load in objects
	TiXmlNode* objects = root->FirstChild("Objects");
	TiXmlNode* obj_iter = objects->FirstChild();
	std::cout << "Loading objects\n";
	while (obj_iter)
	{
	
		// cast the iterator as an element
		TiXmlElement* element = (TiXmlElement*)obj_iter;
		// extract data from element
		int type = atoi(element->Attribute("Type"));
		TiXmlElement* position_element = (TiXmlElement*)element->FirstChild("Position");
		float x = (float)atoi(position_element->Attribute("x"));
		float y = (float)atoi(position_element->Attribute("y"));
		float z = (float)atoi(position_element->Attribute("z"));

		GameObject* obj = nullptr;
		Agent* agent = nullptr;

		// create object based on data
		switch (type)
		{
		case 0:
			obj = (GameObject*)Player::GetInstance()->getTarget();
			obj->AddRef();
			agent = Player::GetInstance();
			break;
		case 1:
			obj = new Shrine;
			break;
		case 2:
			obj = new Temple;
			break;
		}

		// set the objects position
		obj->setPosition(Vector3(x, y, z));
		// add the new object into the object manager
		this->objectManager->AddObject(obj);
		if (agent)
		{
			this->objectManager->AddAgent(agent);
			agent->Release();
		}
		obj->Release();
		// move on to the next node
		obj_iter = obj_iter->NextSibling();
	}

	// load lighting information
	TiXmlNode* lighting_node = root->FirstChild("Lighting");

	// read each light
	TiXmlElement* lights = (TiXmlElement*)lighting_node->FirstChild("Lights");
	TiXmlElement* light_itr = (TiXmlElement*)lights->FirstChild();
	int light_index = 0;
	cout << "Loading lights\n";
	while (light_itr)
	{
		string lightType = light_itr->Value();

		if (lightType == "PointLight")
		{
			TiXmlElement* position_node = (TiXmlElement*)light_itr->FirstChild("Position");
			TiXmlElement* ambiantColor_node = (TiXmlElement*)light_itr->FirstChild("AmbiantColor");
			TiXmlElement* diffuseColor_node = (TiXmlElement*)light_itr->FirstChild("DiffuseColor");
			TiXmlElement* specularColor_node = (TiXmlElement*)light_itr->FirstChild("SpecularColor");
			TiXmlElement* range_node = (TiXmlElement*)light_itr->FirstChild("Range");

			Vector3 ambiantColor,
				diffuseColor,
				specularColor,
				position;

			position.x = (float)atof(position_node->Attribute("x"));
			position.y = (float)atof(position_node->Attribute("y"));
			position.z = (float)atof(position_node->Attribute("z"));

			ambiantColor.x = (float)atof(ambiantColor_node->Attribute("r"));
			ambiantColor.y = (float)atof(ambiantColor_node->Attribute("g"));
			ambiantColor.z = (float)atof(ambiantColor_node->Attribute("b"));

			diffuseColor.x = (float)atof(diffuseColor_node->Attribute("r"));
			diffuseColor.y = (float)atof(diffuseColor_node->Attribute("g"));
			diffuseColor.z = (float)atof(diffuseColor_node->Attribute("b"));

			specularColor.x = (float)atof(specularColor_node->Attribute("r"));
			specularColor.y = (float)atof(specularColor_node->Attribute("g"));
			specularColor.z = (float)atof(specularColor_node->Attribute("b"));

			float range = (float)atof(range_node->GetText());

			PointLight* light = new PointLight;

			light->diffuseColor = diffuseColor;
			light->ambientColor = ambiantColor;
			light->specularColor = specularColor;
			light->position = position;
			light->range = range;

			LightingEngine::GetInstance()->AddLight<PointLight>(light);

			light_index++;
			light_itr = (TiXmlElement*)light_itr->NextSibling();
		}
		else if (lightType == "DirectionalLight")
		{
			TiXmlElement* direction_node = (TiXmlElement*)light_itr->FirstChild("Direction");
			TiXmlElement* ambiantColor_node = (TiXmlElement*)light_itr->FirstChild("AmbiantColor");
			TiXmlElement* diffuseColor_node = (TiXmlElement*)light_itr->FirstChild("DiffuseColor");
			TiXmlElement* specularColor_node = (TiXmlElement*)light_itr->FirstChild("SpecularColor");

			Vector4 ambiantColor,
				diffuseColor,
				specularColor,
				direction;

			direction.x = (float)atof(direction_node->Attribute("x"));
			direction.y = (float)atof(direction_node->Attribute("y"));
			direction.z = (float)atof(direction_node->Attribute("z"));

			ambiantColor.x = (float)atof(ambiantColor_node->Attribute("r"));
			ambiantColor.y = (float)atof(ambiantColor_node->Attribute("g"));
			ambiantColor.z = (float)atof(ambiantColor_node->Attribute("b"));

			diffuseColor.x = (float)atof(diffuseColor_node->Attribute("r"));
			diffuseColor.y = (float)atof(diffuseColor_node->Attribute("g"));
			diffuseColor.z = (float)atof(diffuseColor_node->Attribute("b"));

			specularColor.x = (float)atof(specularColor_node->Attribute("r"));
			specularColor.y = (float)atof(specularColor_node->Attribute("g"));
			specularColor.z = (float)atof(specularColor_node->Attribute("b"));
			
			DirectionalLight* light = new DirectionalLight;

			light->diffuseColor = diffuseColor;
			light->ambientColor = ambiantColor;
			light->specularColor = specularColor;
			light->direction = direction;

			LightingEngine::GetInstance()->AddLight<DirectionalLight>(light);

			light_index++;
			light_itr = (TiXmlElement*)light_itr->NextSibling();

		}
	}

	Heightmap* heightMap;
	cout << "Loading terrain" << endl;
	TiXmlElement* heightMapNode = (TiXmlElement*)root->FirstChild("Heightmap");
	{
		TiXmlAttribute* filenameNode = (TiXmlAttribute*)heightMapNode->FirstAttribute();
		TiXmlElement* highestNode = (TiXmlElement*)heightMapNode->FirstChild("Highest");
		TiXmlElement* lowestNode = (TiXmlElement*)heightMapNode->FirstChild("Lowest");
		TiXmlElement* widthNode = (TiXmlElement*)heightMapNode->FirstChild("Width");
		TiXmlElement* hightNode = (TiXmlElement*)heightMapNode->FirstChild("Height");

		const char* filename = filenameNode->Value();
		const char* highest_tex = highestNode->GetText();
		const char* lowest_tex = lowestNode->GetText();
		const char* width_tex = widthNode->GetText();
		const char* hight_tex = hightNode->GetText();

		float highest = (float)atof(highest_tex);
		float lowest = (float)atof(lowest_tex);
		unsigned int width = (unsigned int)atoi(width_tex) * 20;
		unsigned int height = (unsigned int)atoi(hight_tex) * 20;

		string filePathName = string("Content/Xml/") + filename;
		heightMap = new Heightmap(filePathName.c_str(), width, height, lowest, highest);
	}

	terrain = new Terrain(heightMap);

	delete doc;
}

/*virtual*/ Chunk::~Chunk(void)
{
	terrain->Release();
	objectManager->Release();
	delete Player::GetInstance();
	_CrtCheckMemory();
}

/*virtual*/ void Chunk::Update(float dt) /*override*/
{
	terrain->Update(dt);
	objectManager->Update(dt);
}

/*virtual*/ void Chunk::Draw(void) /*override*/
{
	terrain->Draw();
	objectManager->Draw();
}